﻿/*
 * The MIT License
 * 
 * Copyright (c) 2010, Shinichi Takano
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace COM.General
{
    public class AutoCOMObject<COMTYPE> : IDisposable where COMTYPE : class
    {
        COMTYPE _o;

        //bool bApp = false;

        public AutoCOMObject(COMTYPE o)
        {
            if (!System.Runtime.InteropServices.Marshal.IsComObject(o)) throw new Exception("not a COM object");
            _o = o;
            Detached = false;
            //int refCnt = System.Runtime.InteropServices.Marshal.AddRef(System.Runtime.InteropServices.Marshal.GetIUnknownForObject(_o));

            //bApp = o is Microsoft.Office.Interop.Access.Application;
            //System.Diagnostics.Debug.WriteLineIf(bApp, "AddRef:" + refCnt.ToString());
        }

        ~AutoCOMObject()
        {
            Dispose();
        }

        public COMTYPE Value
        {
            get
            {
                if (!HasValidRCW) throw new Exception("RCW is not valid");
                return _o;
            }
        }

        public bool HasValidRCW
        {
            get
            {
                IntPtr p = IntPtr.Zero;
                try
                {
                    p = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(_o);
                    if (p == IntPtr.Zero) return false;
                    return true;
                }
                catch
                {
                    return false;
                }
                finally
                {
                    if (p != IntPtr.Zero) System.Runtime.InteropServices.Marshal.Release(p);
                }
            }
        }

        #region IDisposable メンバ

        public void Dispose()
        {
            if (_o == null || Detached) return;

            int refCnt = System.Runtime.InteropServices.Marshal.ReleaseComObject(_o);
            //System.Diagnostics.Debug.WriteLineIf(bApp, "ReleaseComObject:" + refCnt.ToString());

            _o = null;
        }

        #endregion

        public AutoCOMObject<COMTYPE> Clone
        {
            get
            {
                if (Detached) throw new InvalidProgramException();
                Detached = true;
                return new AutoCOMObject<COMTYPE>(_o);
            }
        }

        public bool Detached
        {
            get;
            private set;
        }
    }
}